package com.ayuku.commons;

import net.sf.paperclips.GridPrint;
import net.sf.paperclips.PageDecoration;
import net.sf.paperclips.PageNumber;
import net.sf.paperclips.PageNumberPrint;
import net.sf.paperclips.PagePrint;
import net.sf.paperclips.PaperClips;
import net.sf.paperclips.Print;
import net.sf.paperclips.PrintJob;
import net.sf.paperclips.TextPrint;
import net.sf.paperclips.ui.PrintPreview;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.printing.PrintDialog;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

public abstract class ReportViewerPaperClips extends
		org.eclipse.swt.widgets.Dialog {

	private Display display;
	private Shell dialogShell;

	private PrintJob printJob;
	ScrolledComposite scroll;
	PrintPreview preview;
	Button previousPage;
	Label pageNumber;
	Button nextPage;
	private int margin = 10;
	private float zoomAmt = 2.2f;

	public float getZoomAmt() {
		return zoomAmt;
	}

	public void setZoomAmt(float zoomAmt) {
		this.zoomAmt = zoomAmt;
	}

	public int getMargin() {
		return margin;
	}

	public void setMargin(int margin) {
		this.margin = margin;
	}

	double[] scrollingPosition;

	public ReportViewerPaperClips(Shell parent, int style) {
		super(parent, style);
		this.display = parent.getDisplay();
	}

	public void directPrint() {
		try {
			createDirectPrint();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void open() {
		try {
			Shell parent = getParent();
			dialogShell = new Shell(parent, SWT.DIALOG_TRIM
					| SWT.APPLICATION_MODAL | SWT.RESIZE);

			dialogShell.setLayout(new FormLayout());
			dialogShell.layout();
			// dialogShell.pack();
			createShell();
			Util.setSize(dialogShell, 780, 500);
			Util.setCenter(dialogShell);
			dialogShell.open();
			setPreviewScale(getZoomAmt());
			Display display = dialogShell.getDisplay();
			while (!dialogShell.isDisposed()) {
				if (!display.readAndDispatch())
					display.sleep();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public abstract Print createBody();

	public abstract String getReportTitle();

	public void createShell(){

		printJob = new PrintJob(getReportTitle(), createPrint())
				.setMargins(getMargin()); // 1.5"

		dialogShell.setText(getReportTitle());
		// dialogShell.setBounds(100, 100, 800, 600);
		dialogShell.setLayout(new GridLayout(1, false));

		createButtonPanel(dialogShell).setLayoutData(
				new GridData(SWT.FILL, SWT.FILL, true, false));
		createScrollingPreview(dialogShell).setLayoutData(
				new GridData(SWT.FILL, SWT.FILL, true, true));

		preview.setPrintJob(printJob);

		updatePreviewSize();
		updatePageNumber();

		// dialogShell.setVisible(true);
	}

	public void createDirectPrint(){
		printJob = new PrintJob(getReportTitle(), createPrint())
				.setMargins(getMargin());
		PaperClips.print(printJob, new PrinterData());
	}

	private Control createButtonPanel(Composite parent) {
		Composite composite = new Composite(parent, SWT.NONE);

		GridLayout layout = new GridLayout(16, false);
		layout.marginWidth = layout.marginHeight = 0;
		composite.setLayout(layout);

		previousPage = createIconButton(composite, "images/previous_page.gif",
				"Previous Page", new Listener() {
					public void handleEvent(Event event) {
						setPreviewPageIndex(preview.getPageIndex()
								- preview.getHorizontalPageCount()
								* preview.getVerticalPageCount());
					}
				});

		pageNumber = new Label(composite, SWT.NONE);

		nextPage = createIconButton(composite, "images/next_page.gif",
				"Next Page", new Listener() {
					public void handleEvent(Event event) {
						setPreviewPageIndex(preview.getPageIndex()
								+ preview.getHorizontalPageCount()
								* preview.getVerticalPageCount());
					}
				});

		createIconButton(composite, "images/fit_horizontal.png", "Fit Width",
				new Listener() {
					public void handleEvent(Event event) {
						preview.setFitHorizontal(true);
						preview.setFitVertical(false);
						rememberScrollingPosition();
						updatePreviewSize();
						restoreScrollingPosition();
					}
				});

		createIconButton(composite, "images/fit_vertical.png", "Fit Height",
				new Listener() {
					public void handleEvent(Event event) {
						preview.setFitVertical(true);
						preview.setFitHorizontal(false);
						rememberScrollingPosition();
						updatePreviewSize();
						restoreScrollingPosition();
					}
				});

		createIconButton(composite, "images/fit_best.png", "Fit Window",
				new Listener() {
					public void handleEvent(Event event) {
						preview.setFitVertical(true);
						preview.setFitHorizontal(true);
						rememberScrollingPosition();
						updatePreviewSize();
						restoreScrollingPosition();
					}
				});

		createIconButton(composite, "images/zoom_in.gif", "Zoom In",
				new Listener() {
					public void handleEvent(Event event) {
						setPreviewScale(preview.getAbsoluteScale() * 1.1f);
					}
				});

		createIconButton(composite, "images/zoom_out.gif", "Zoom Out",
				new Listener() {
					public void handleEvent(Event event) {
						setPreviewScale(preview.getAbsoluteScale() / 1.1f);
					}
				});

		createIconButton(composite, "images/zoom_scale.gif", "Zoom to Scale",
				new Listener() {
					public void handleEvent(Event event) {
						setPreviewScale(1);
					}
				});

		createTextButton(composite, "Port", "Portrait Orientation",
				new Listener() {
					public void handleEvent(Event event) {
						printJob
								.setOrientation(PaperClips.ORIENTATION_PORTRAIT);
						preview.setPrintJob(printJob);

						forgetScrollingPosition();
						updatePreviewSize();
						updatePageNumber();
					}
				});

		createTextButton(composite, "Land", "Landscape Orientation",
				new Listener() {
					public void handleEvent(Event event) {
						printJob
								.setOrientation(PaperClips.ORIENTATION_LANDSCAPE);
						preview.setPrintJob(printJob);

						forgetScrollingPosition();
						updatePreviewSize();
						updatePageNumber();
					}
				});

		createIconButton(composite, "images/print.gif", "Print",
				new Listener() {
					public void handleEvent(Event event) {
						PrintDialog dialog = new PrintDialog(dialogShell,
								SWT.NONE);
						PrinterData printerData = dialog.open();
						if (printerData != null) {
							PaperClips.print(printJob, printerData);
							preview.setPrinterData(printerData);
						}
					}
				});
		/*
		 * createLabel(composite, "Horz Pages");
		 * createPageCountSpinner(composite, new Listener() { public void
		 * handleEvent(Event event) { preview.setHorizontalPageCount(((Spinner)
		 * event.widget) .getSelection()); forgetScrollingPosition();
		 * updatePreviewSize(); updatePageNumber(); } });
		 * 
		 * createLabel(composite, "Vert Pages");
		 * createPageCountSpinner(composite, new Listener() { public void
		 * handleEvent(Event event) { preview.setVerticalPageCount(((Spinner)
		 * event.widget) .getSelection()); forgetScrollingPosition();
		 * updatePreviewSize(); updatePageNumber(); } });
		 */

		return composite;
	}

	private Control createScrollingPreview(Composite parent) {
		scroll = new ScrolledComposite(parent, SWT.BORDER | SWT.H_SCROLL
				| SWT.V_SCROLL);
		scroll.setExpandHorizontal(true);
		scroll.setExpandVertical(true);

		preview = new PrintPreview(scroll, SWT.NONE);
		scroll.setContent(preview);

		scroll.addListener(SWT.Resize, new Listener() {
			public void handleEvent(Event event) {
				Rectangle bounds = scroll.getClientArea();

				scroll.getHorizontalBar()
						.setPageIncrement(bounds.width * 2 / 3);
				scroll.getVerticalBar().setPageIncrement(bounds.height * 2 / 3);

				if (preview.isFitHorizontal() ^ preview.isFitVertical()) {
					rememberScrollingPosition();
					updatePreviewSize();
					restoreScrollingPosition();
				}
			}
		});

		preview.setFitVertical(true);
		preview.setFitHorizontal(true);

		Listener dragListener = new Listener() {

			private final Point dpi = display.getDPI();
			private boolean scrollable = false;

			private boolean dragging = false;
			private Point dragStartScrollOrigin = null;
			private Point dragStartMouseAnchor = null;

			public void handleEvent(Event event) {
				switch (event.type) {
				case SWT.Resize:
					forgetScrollingPosition();
					Rectangle bounds = scroll.getClientArea();
					Point size = preview.getSize();
					scrollable = size.x > bounds.width
							|| size.y > bounds.height;
					if (!scrollable && dragging)
						endDragging();
					break;
				case SWT.MouseDown:
					forgetScrollingPosition();
					if (scrollable && event.button == 1)
						beginDragging(event);
					break;
				case SWT.MouseMove:
					if (dragging) {
						forgetScrollingPosition();
						Point point = preview.toDisplay(event.x, event.y);
						scroll.setOrigin(dragStartScrollOrigin.x
								+ dragStartMouseAnchor.x - point.x,
								dragStartScrollOrigin.y
										+ dragStartMouseAnchor.y - point.y);
					}
					break;
				case SWT.MouseUp:
					forgetScrollingPosition();
					if (dragging)
						endDragging();
					break;
				case SWT.MouseEnter:
					display.addFilter(SWT.MouseWheel, this);
					break;
				case SWT.MouseWheel:
					if (event.count != 0) {
						if (scrollable
								&& !dragging
								&& (event.stateMask == SWT.NONE || event.stateMask == SWT.SHIFT)) {
							forgetScrollingPosition();
							bounds = scroll.getClientArea();
							size = preview.getSize();
							Point origin = scroll.getOrigin();
							int direction = event.count > 0 ? -1 : 1;
							// Prefer vertical scrolling unless user is
							// pressing Shift
							if (size.y > bounds.height
									&& event.stateMask == SWT.NONE)
								origin.y += direction
										* Math.min(dpi.y, bounds.height / 4);
							else if (size.x > bounds.width)
								origin.x += direction
										* Math.min(dpi.x, bounds.width / 4);
							scroll.setOrigin(origin);
							event.doit = false;
						} else if (event.stateMask == SWT.CTRL) { // Ctrl+MouseWheel
							// ->
							// zoom
							float scale = preview.getAbsoluteScale();
							setPreviewScale(event.count > 0 ? scale / 1.1f
									: scale * 1.1f);
						}
					}
					break;
				case SWT.MouseExit:
					display.removeFilter(SWT.MouseWheel, this);
					break;
				}
			}

			private void beginDragging(Event event) {
				dragStartScrollOrigin = scroll.getOrigin();
				dragStartMouseAnchor = preview.toDisplay(event.x, event.y);
				dragging = true;
			}

			private void endDragging() {
				dragging = false;
				dragStartMouseAnchor = null;
				dragStartScrollOrigin = null;
			}
		};

		scroll.addListener(SWT.Resize, dragListener);
		preview.addListener(SWT.MouseDown, dragListener);
		preview.addListener(SWT.MouseMove, dragListener);
		preview.addListener(SWT.MouseUp, dragListener);

		// These are for mouse wheel handling
		preview.addListener(SWT.MouseEnter, dragListener);
		preview.addListener(SWT.MouseExit, dragListener);

		return scroll;
	}

	private Button createIconButton(Composite parent, String imageFilename,
			String toolTipText, Listener selectionListener) {
		Button button = createButton(parent, toolTipText, selectionListener);
		button.setImage(createImage(imageFilename));
		return button;
	}

	private Button createTextButton(Composite parent, String text,
			String toolTipText, Listener selectionListener) {
		Button button = createButton(parent, toolTipText, selectionListener);
		button.setText(text);
		return button;
	}

	private Button createButton(Composite parent, String toolTipText,
			Listener selectionListener) {
		Button button = new Button(parent, SWT.PUSH);
		button.setToolTipText(toolTipText);
		button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
		button.addListener(SWT.Selection, selectionListener);
		return button;
	}

	private Image createImage(String filename) {
		final Image image = new Image(display, getClass().getResourceAsStream(
				filename));

		dialogShell.addListener(SWT.Dispose, new Listener() {
			public void handleEvent(Event event) {
				image.dispose();
			}
		});

		return image;
	}

	private void updatePageNumber() {
		int pageIndex = preview.getPageIndex();
		int pageCount = preview.getPageCount();
		int visiblePageCount = preview.getHorizontalPageCount()
				* preview.getVerticalPageCount();
		String text = (visiblePageCount > 1 ? "Pages " + (pageIndex + 1) + "-"
				+ Math.min(pageCount, pageIndex + visiblePageCount) : "Page "
				+ (pageIndex + 1))
				+ " of " + pageCount;
		pageNumber.setText(text);
		previousPage.setEnabled(pageIndex > 0);
		nextPage.setEnabled(pageIndex < pageCount - visiblePageCount);
		dialogShell.layout(new Control[] { pageNumber });
	}

	private void rememberScrollingPosition() {
		Point size = preview.getSize();
		if (size.x == 0 || size.y == 0) {
			forgetScrollingPosition();
		} else if (scrollingPosition == null) {
			Point origin = scroll.getOrigin();
			scrollingPosition = new double[] {
					(double) origin.x / (double) size.x,
					(double) origin.y / (double) size.y };
		}
	}

	private void forgetScrollingPosition() {
		scrollingPosition = null;
	}

	private void restoreScrollingPosition() {
		if (scrollingPosition != null) {
			Point size = preview.getSize();
			scroll.setOrigin((int) Math.round(scrollingPosition[0] * size.x),
					(int) Math.round(scrollingPosition[1] * size.y));
		}
	}

	private void updatePreviewSize() {
		Point minSize;
		Rectangle bounds = scroll.getClientArea();
		if (preview.isFitHorizontal()) {
			if (preview.isFitVertical())
				minSize = new Point(0, 0); // Best fit
			else
				minSize = new Point(0, preview.computeSize(bounds.width,
						SWT.DEFAULT).y); // Fit to width
		} else {
			if (preview.isFitVertical())
				minSize = new Point(preview.computeSize(SWT.DEFAULT,
						bounds.height).x, 0); // Fit to height
			else
				minSize = preview.computeSize(SWT.DEFAULT, SWT.DEFAULT); // Custom
			// scale
		}
		scroll.setMinSize(minSize);
	}

	public void setPreviewScale(float scale) {
		preview.setFitVertical(false);
		preview.setFitHorizontal(false);
		preview.setScale(scale);
		rememberScrollingPosition();
		updatePreviewSize();
		restoreScrollingPosition();
	}

	public Print createPrint()  {
		Print prnt =  createBody();
		if (prnt==null){
			Util.showMsgBox("Tidak ada data", 1, dialogShell);
			return null;
		}
		
		PagePrint page = new PagePrint(prnt);
		return page;
	}

	private void setPreviewPageIndex(int pageIndex) {
		preview.setPageIndex(Math.max(Math.min(pageIndex, preview
				.getPageCount() - 1), 0));
		updatePageNumber();
	}

	public static PageDecoration createHeader() {
		PageDecoration header = new PageDecoration() {
			public Print createPrint(PageNumber pageNumber) {
				GridPrint grid = new GridPrint("d:g, r:d");
				grid.add(new TextPrint("Surver Girl"));
				grid.add(new PageNumberPrint(pageNumber, SWT.RIGHT));
				return grid;
			}
		};
		return header;
	}

	public static PageDecoration createFooter() {
		PageDecoration footer = new PageDecoration() {
			public Print createPrint(PageNumber pageNumber) {
				GridPrint grid = new GridPrint("d:g, r:d");
				grid.add(new TextPrint("Ini Footer"));
				grid.add(new PageNumberPrint(pageNumber, SWT.RIGHT));
				return grid;
			}
		};
		return footer;
	}

}
